﻿using RRQMCore;
using RRQMCore.Run;
using RRQMSocket.FileTransfer;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FileTransferClientDemo
{
    public partial class Form1 : Form
    {
        private FileClient fileClient;
        private bool showPathBox = false;
        private bool showLoop = false;
        private string pathSuggesttion = string.Empty;

        private FileCheckerType fileCheckType = FileCheckerType.MD5;

        private const string SUGGEST_SERVER_SAVE_FILENAME = "請指定文件名（包含擴展名）";

        private Thread pushThread, pullThread;

        public Form1()
        {
            InitializeComponent();
            fileCheckCmb.SelectedIndex = 0;
        }

        private void showMsg(string msg) 
        {
            invokeOnUI(() => { this.msgBox.AppendText(msg + "\r\n"); });
        }

        private void syncLoopDefin() 
        {
            invokeOnUI(()=> {
                this.loopBox.Visible = showLoop;
                this.loopLb.Visible = showLoop;
            });
        }

        private void syncPathInput() 
        {
            invokeOnUI(()=> {
                this.fileNameLb.Visible = showPathBox;
                this.fileNameBox.Text = pathSuggesttion;
                this.fileNameBox.Visible = showPathBox;
            });
        }

        private void invokeOnUI(Action action) 
        {
            Invoke(action);
        }

        private void connectBtn_Click(object sender, EventArgs e)
        {
            if (fileClient != null  && fileClient.Online ) 
            {
                showMsg("已連上服務端，不要重複連接");
                return;
            }

            int port = 7789;
            string token = "FileTransferDemo";
            string serverIp = "127.0.0.1";

            if (!"".Equals(portBox.Text)) 
            {
                try 
                { 
                    port = Convert.ToInt32(portBox.Text); 
                } 
                catch (Exception exp) 
                { 
                    showMsg("非法Port : " + portBox.Text + " Exception ==> " + exp.ToString());
                    return;
                }
            }

            if (!"".Equals(ipBox.Text)) 
            {
                serverIp = ipBox.Text;
            }

            if (!"".Equals(tokenBox.Text)) 
            {
                token = tokenBox.Text;
            }

            if (string.IsNullOrEmpty(rootPathBox.Text)) 
            {
                showMsg("請指定RootPath（存放位置）");
                return;
            }

            if ( !Directory.Exists(rootPathBox.Text) ) 
            {
                showMsg("指定的RootPath（存放位置）不存在");
                return;
            }

            fileClient = new FileClient();
            fileClient.Disconnected += FileClient_Disconnected;
            fileClient.BeforeFileTransfer += FileClient_BeforeFileTransfer;
            fileClient.FinishedFileTransfer += FileClient_FinishedFileTransfer;
            var config = new FileClientConfig();
            config.RemoteIPHost = new RRQMSocket.IPHost(serverIp + ":" + port);
            config.RootPath = rootPathBox.Text;
            fileClient.Setup(config);

            try
            {
                fileClient.Connect(token);
                fileClient.ClientConfig.KeepAlive = true;
                showMsg("連接成功");
            }
            catch (Exception exp) 
            {
                fileClient = null;
                showMsg("連接失敗 ==> " + exp.ToString());
            }
        }

        private void FileClient_FinishedFileTransfer(FileClient client, FileTransferStatusEventArgs e)
        {
            string transferType = e.TransferType == TransferType.Push ? "Push" : "Pull";
            showMsg($"{transferType} 傳輸即將成功: {e.FileRequest.SavePath}");
        }

        private void FileClient_BeforeFileTransfer(FileClient client, FileOperationEventArgs e)
        {
            showMsg($"{DateTime.Now.ToString("yyyy-MM-dd  HH:mm:ss")} Transfer Start: {e.FileRequest.SavePath}");
        }

        private void FileClient_Disconnected(RRQMSocket.ITcpClient client, RRQMSocket.MesEventArgs e)
        {
            showMsg("連接已斷開 ==> " + e.Message);
            if (fileClient != null) 
            {
                fileClient.Dispose();
            }
            fileClient = null;
        }

        private void pushFile(object sender, EventArgs e)
        {
            if (fileClient == null || !fileClient.Online) 
            {
                showMsg("尚未連接到服務端或連接已斷開");
                return;
            }

            if (pushThread != null && pushThread.IsAlive) 
            {
                showMsg("推送任務進行中，請等待推送完成");
                return;
            }

            if (!fileNameBox.Visible) 
            {
                pathSuggesttion = SUGGEST_SERVER_SAVE_FILENAME;
                showPathBox = true;
                syncPathInput();
                return;
            }

            string desFileName = fileNameBox.Text;

            if (SUGGEST_SERVER_SAVE_FILENAME.Equals(desFileName) || "".Equals(desFileName)) 
            {
                showMsg(SUGGEST_SERVER_SAVE_FILENAME);
                return;
            }

            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.ShowDialog();
            string sourceFileName = openFileDialog.FileName;
            if (string.IsNullOrWhiteSpace(sourceFileName)) 
            {
                showMsg("非法文件名，空的");
                return;
            }

            pushThread = new Thread(()=> {
                try
                {
                    FileRequest fileRequest = new FileRequest(sourceFileName, desFileName);
                    fileRequest.Overwrite = overWriteCb.Checked;
                    fileRequest.FileCheckerType = fileCheckType;
                    fileRequest.Flags = TransferFlags.BreakpointResume;

                    FileOperator fileOperator = new FileOperator();
                    LoopAction loopAction = null;
                    if (showTransferSpeedCb.Checked)
                    {
                        loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) => {
                            if (fileOperator.Result.ResultCode != ResultCode.Default)
                            {
                                loop.Dispose();
                                return;
                            }
                            showMsg($"PushFile {sourceFileName} 進度 : {fileOperator.Progress * 100}%, 速度 : {fileOperator.Speed()} Byte/S");
                        });
                        loopAction.RunAsync();
                    }

                    Metadata metadata = new Metadata();
                    metadata.Add("1", "1");
                    metadata.Add("2", "2");
                    showMsg($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} PushFile {sourceFileName} 開始");
                    IResult result = fileClient.PushFile(fileRequest, fileOperator, metadata);
                    while (fileOperator.Result.ResultCode != ResultCode.Success)
                    {
                        Thread.Sleep(500);
                    }
                    showMsg($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} PushFile {sourceFileName} 成功");

                    if (loopAction != null) 
                    {
                        loopAction.Dispose();
                    }
                }
                catch (Exception exp)
                {
                    showMsg("PushFile " + sourceFileName + " fail ==> " + exp.ToString());
                }
            });
            pushThread.Start();
        }

        private void closeConn(object sender, EventArgs e)
        {
            if (fileClient == null || !fileClient.Online) 
            {
                showMsg("已斷開連接");
                return;
            }

            try
            {
                fileClient.Disconnect();
                fileClient.Dispose();
                fileClient = null;
            }
            catch (Exception exp) 
            {
                showMsg("斷開連接失敗 ==> " + exp.ToString());
            }
        }

        private void loopPullBtn_Click(object sender, EventArgs e)
        {

            if (fileClient == null || !fileClient.Online)
            {
                showMsg("尚未連接到服務端或連接已斷開");
                return;
            }

            if (!loopBox.Visible || string.IsNullOrWhiteSpace(loopBox.Text)) 
            {
                showLoop = true;
                syncLoopDefin();
                showMsg("Please define loop count");
                return;
            }

            if (pushThread != null && pushThread.IsAlive)
            {
                showMsg("推送任務進行中，請等待推送完成");
                return;
            }

            int loopCount = 0;
            try
            {
                loopCount = Convert.ToInt32(loopBox.Text);
            }
            catch (Exception exp) 
            {
                showMsg("invalid loop count, please check ==> " + exp.ToString());
                return;
            }

            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.ShowDialog();
            string sourceFileName = openFileDialog.FileName;
            if (string.IsNullOrWhiteSpace(sourceFileName))
            {
                showMsg("invalid file ==> null fileName");
                return;
            }

            string desPath = sourceFileName.Substring(sourceFileName.LastIndexOf("\\") + 1);
            string desName = desPath.Substring(0, desPath.LastIndexOf("."));
            string desSuffix = desPath.Replace(desName,"");
            string desFileName;
            bool lastCompleted = true;
            do
            {
                loopCount--;
                desFileName = desName + loopCount + desSuffix;
                try
                {
                    pushThread = new Thread(()=> {
                        lastCompleted = false;
                        FileRequest fileRequest = new FileRequest(sourceFileName, desFileName);
                        fileRequest.Overwrite = overWriteCb.Checked;
                        fileRequest.FileCheckerType = fileCheckType;
                        fileRequest.Flags = TransferFlags.BreakpointResume;

                        FileOperator fileOperator = new FileOperator();

                        LoopAction loopAction = null;
                        if (showTransferSpeedCb.Checked)
                        {
                            loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) => {
                                if (fileOperator.Result.ResultCode != ResultCode.Default)
                                {
                                    loop.Dispose();
                                    return;
                                }

                                showMsg($"LoopPushTest {desFileName}進度 : {fileOperator.Progress}, 速度 : {fileOperator.Speed()}");
                            });
                            loopAction.RunAsync();
                        }

                        Metadata metadata = new Metadata();
                        metadata.Add("1", "1");
                        metadata.Add("2", "2");

                        IResult result = fileClient.PushFile(fileRequest, fileOperator, metadata);

                        showMsg($"LoopPushTest Transfer Start: {sourceFileName} to {desFileName}");
                        while (fileOperator.Result.ResultCode != ResultCode.Success)
                        {
                            Thread.Sleep(500);
                        }
                        showMsg($"LoopPushTest 傳輸成功: {sourceFileName} to {desFileName}");

                        if (loopAction != null)
                        {
                            loopAction.Dispose();
                        }

                        lastCompleted = true;
                    });
                    pushThread.Start();

                    while (!lastCompleted) 
                    {
                        Thread.Sleep(500);
                    }
                }
                catch (Exception exp)
                {
                    showMsg($"LoopPushTest  {sourceFileName} to {desFileName}  fail ==> {exp.ToString()}");
                }

            } while (loopCount > 0);
        }

        private void pullBtn_Click(object sender, EventArgs e)
        {
            if (fileClient == null || !fileClient.Online)
            {
                showMsg("尚未連接到服務端或連接已斷開");
                return;
            }

            if (pullThread != null && pullThread.ThreadState == ThreadState.Running) 
            {
                showMsg("文件拉取進行中，請等待拉取完成");
                return;
            }

            if (!fileNameBox.Visible)
            {
                pathSuggesttion = SUGGEST_SERVER_SAVE_FILENAME;
                showPathBox = true;
                syncPathInput();
                return;
            }

            string fileName = fileNameBox.Text;

            if (SUGGEST_SERVER_SAVE_FILENAME.Equals(fileName) || "".Equals(fileName))
            {
                showMsg("請指定要拉取的文件名（包含擴展名）");
                return;
            }

            pullThread = new Thread( () => {
                FileRequest fileRequest = new FileRequest(fileName, fileName);
                fileRequest.Overwrite = overWriteCb.Checked;
                fileRequest.FileCheckerType = fileCheckType;
                fileRequest.Flags = TransferFlags.BreakpointResume;

                FileOperator fileOperator = new FileOperator();
                LoopAction loopAction = null;
                if (showTransferSpeedCb.Checked) 
                {
                    loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) => {
                        if (fileOperator.Result.ResultCode != ResultCode.Default)
                        {
                            loop.Dispose();
                            return;
                        }
                        showMsg($"PullFile {fileName} 進度 : {fileOperator.Progress * 100}%, 速度 : {fileOperator.Speed()} Byte/S");
                    });
                    loopAction.RunAsync();
                }

                Metadata metadata = new Metadata();
                metadata.Add("1", "1");
                metadata.Add("2", "2");
                showMsg($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} PullFile {fileName} 開始");
                IResult result = fileClient.PullFile(fileRequest, fileOperator, metadata);
                while (fileOperator.Result.ResultCode != ResultCode.Success)
                {
                    Thread.Sleep(500);
                }
                showMsg($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} PullFile {fileName} 成功");

                if (loopAction != null) 
                {
                    loopAction.Dispose();
                }
            });

            pullThread.Start();
        }

        private void clearMsg(object sender, EventArgs e)
        {
            invokeOnUI(()=> {
                msgBox.Clear();
            });
        }

        private void fileCheckCmb_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (fileCheckCmb.SelectedItem.ToString()) 
            {
                case "MD5":
                    fileCheckType = FileCheckerType.MD5;
                    break;
                case "SHA1":
                    fileCheckType = FileCheckerType.SHA1;
                    break;
                default:
                    fileCheckType = FileCheckerType.None;
                    break;
            }
        }
    }
}
